/** * * Copyright 2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.geronimo.transaction.manager; import java.util.ArrayList; import java.util.Map; import javax.management.ObjectName; import javax.transaction.RollbackException; import javax.transaction.Status; import javax.transaction.Transaction; import javax.transaction.xa.XAResource; import javax.transaction.xa.Xid; import junit.framework.TestCase; import org.apache.geronimo.gbean.ReferenceCollection; import org.apache.geronimo.gbean.ReferenceCollectionEvent; import org.apache.geronimo.gbean.ReferenceCollectionListener; /** * @version $Rev$ $Date$ */ public class TransactionManagerImplTest extends TestCase { MockResourceManager rm1 = new MockResourceManager(true); MockResource r1_1 = rm1.getResource("rm1_1"); MockResource r1_2 = rm1.getResource("rm1_2"); MockResourceManager rm2 = new MockResourceManager(true); MockResource r2_1 = rm2.getResource("rm2_1"); MockResource r2_2 = rm2.getResource("rm2_2"); TransactionLog transactionLog = new MockLog(); ReferenceCollection resourceManagers = new TestReferenceCollection(); TransactionManagerImpl tm; protected void setUp() throws Exception { tm = new TransactionManagerImplGBean(10, new XidFactoryImpl("WHAT DO WE CALL IT?".getBytes()), transactionLog, resourceManagers); } protected void tearDown() throws Exception { tm = null; } public void testNoResourcesCommit() throws Exception { assertEquals(Status.STATUS_NO_TRANSACTION, tm.getStatus()); tm.begin(); assertEquals(Status.STATUS_ACTIVE, tm.getStatus()); tm.commit(); assertNull(tm.getTransaction()); assertEquals(Status.STATUS_NO_TRANSACTION, tm.getStatus()); tm.begin(); assertEquals(Status.STATUS_ACTIVE, tm.getStatus()); Transaction tx = tm.getTransaction(); assertNotNull(tx); tx.commit(); assertNotNull(tm.getTransaction()); assertEquals(Status.STATUS_NO_TRANSACTION, tm.getStatus()); } public void testNoResourcesMarkRollbackOnly() throws Exception { assertEquals(Status.STATUS_NO_TRANSACTION, tm.getStatus()); tm.begin(); assertEquals(Status.STATUS_ACTIVE, tm.getStatus()); tm.getTransaction().setRollbackOnly(); assertEquals(Status.STATUS_MARKED_ROLLBACK, tm.getStatus()); try { tm.commit(); fail("tx should not commit"); } catch (RollbackException e) { //expected } assertNull(tm.getTransaction()); assertEquals(Status.STATUS_NO_TRANSACTION, tm.getStatus()); tm.begin(); assertEquals(Status.STATUS_ACTIVE, tm.getStatus()); Transaction tx = tm.getTransaction(); assertNotNull(tx); tx.setRollbackOnly(); assertEquals(Status.STATUS_MARKED_ROLLBACK, tx.getStatus()); try { tx.commit(); fail("tx should not commit"); } catch (RollbackException e) { //expected } assertNotNull(tm.getTransaction()); assertEquals(Status.STATUS_NO_TRANSACTION, tm.getStatus()); } public void testNoResourcesRollback() throws Exception { assertEquals(Status.STATUS_NO_TRANSACTION, tm.getStatus()); tm.begin(); assertEquals(Status.STATUS_ACTIVE, tm.getStatus()); tm.rollback(); assertNull(tm.getTransaction()); assertEquals(Status.STATUS_NO_TRANSACTION, tm.getStatus()); tm.begin(); assertEquals(Status.STATUS_ACTIVE, tm.getStatus()); Transaction tx = tm.getTransaction(); assertNotNull(tx); tx.rollback(); assertNotNull(tm.getTransaction()); assertEquals(Status.STATUS_NO_TRANSACTION, tm.getStatus()); //check rollback when marked rollback only tm.begin(); assertEquals(Status.STATUS_ACTIVE, tm.getStatus()); tm.getTransaction().setRollbackOnly(); assertEquals(Status.STATUS_MARKED_ROLLBACK, tm.getStatus()); tm.rollback(); assertNull(tm.getTransaction()); assertEquals(Status.STATUS_NO_TRANSACTION, tm.getStatus()); } public void testOneResourceCommit() throws Exception { assertEquals(Status.STATUS_NO_TRANSACTION, tm.getStatus()); tm.begin(); Transaction tx = tm.getTransaction(); tx.enlistResource(r1_1); tx.delistResource(r1_1, XAResource.TMSUCCESS); tx.commit(); assertEquals(Status.STATUS_NO_TRANSACTION, tm.getStatus()); assertTrue(r1_1.isCommitted()); assertTrue(!r1_1.isPrepared()); assertTrue(!r1_1.isRolledback()); } public void testOneResourceMarkedRollback() throws Exception { assertEquals(Status.STATUS_NO_TRANSACTION, tm.getStatus()); tm.begin(); Transaction tx = tm.getTransaction(); tx.enlistResource(r1_1); tx.setRollbackOnly(); tx.delistResource(r1_1, XAResource.TMSUCCESS); try { tx.commit(); fail("tx should roll back"); } catch (RollbackException e) { //expected } assertEquals(Status.STATUS_NO_TRANSACTION, tm.getStatus()); assertTrue(!r1_1.isCommitted()); assertTrue(!r1_1.isPrepared()); assertTrue(r1_1.isRolledback()); } public void testOneResourceRollback() throws Exception { assertEquals(Status.STATUS_NO_TRANSACTION, tm.getStatus()); tm.begin(); Transaction tx = tm.getTransaction(); tx.enlistResource(r1_1); tx.delistResource(r1_1, XAResource.TMSUCCESS); tx.rollback(); assertEquals(Status.STATUS_NO_TRANSACTION, tm.getStatus()); assertTrue(!r1_1.isCommitted()); assertTrue(!r1_1.isPrepared()); assertTrue(r1_1.isRolledback()); } public void testTwoResourceOneRMCommit() throws Exception { assertEquals(Status.STATUS_NO_TRANSACTION, tm.getStatus()); tm.begin(); Transaction tx = tm.getTransaction(); tx.enlistResource(r1_1); tx.delistResource(r1_1, XAResource.TMSUCCESS); tx.enlistResource(r1_2); tx.delistResource(r1_2, XAResource.TMSUCCESS); tx.commit(); assertEquals(Status.STATUS_NO_TRANSACTION, tm.getStatus()); assertTrue(r1_1.isCommitted() ^ r1_2.isCommitted()); assertTrue(!r1_1.isPrepared() & !r1_2.isPrepared()); assertTrue(!r1_1.isRolledback() & !r1_2.isRolledback()); } public void testTwoResourceOneRMMarkRollback() throws Exception { assertEquals(Status.STATUS_NO_TRANSACTION, tm.getStatus()); tm.begin(); Transaction tx = tm.getTransaction(); tx.enlistResource(r1_1); tx.delistResource(r1_1, XAResource.TMSUCCESS); tx.enlistResource(r1_2); tx.delistResource(r1_2, XAResource.TMSUCCESS); tx.setRollbackOnly(); try { tx.commit(); fail("tx should roll back"); } catch (RollbackException e) { //expected } assertEquals(Status.STATUS_NO_TRANSACTION, tm.getStatus()); assertTrue(!r1_1.isCommitted() & !r1_2.isCommitted()); assertTrue(!r1_1.isPrepared() & !r1_2.isPrepared()); assertTrue(r1_1.isRolledback() ^ r1_2.isRolledback()); } public void testTwoResourcesOneRMRollback() throws Exception { tm.begin(); Transaction tx = tm.getTransaction(); tx.enlistResource(r1_1); tx.delistResource(r1_1, XAResource.TMSUCCESS); tx.enlistResource(r1_2); tx.delistResource(r1_2, XAResource.TMSUCCESS); tx.setRollbackOnly(); tx.rollback(); assertEquals(Status.STATUS_NO_TRANSACTION, tm.getStatus()); assertTrue(!r1_1.isCommitted() & !r1_2.isCommitted()); assertTrue(!r1_1.isPrepared() & !r1_2.isPrepared()); assertTrue(r1_1.isRolledback() ^ r1_2.isRolledback()); } public void testFourResourceTwoRMCommit() throws Exception { assertEquals(Status.STATUS_NO_TRANSACTION, tm.getStatus()); tm.begin(); Transaction tx = tm.getTransaction(); tx.enlistResource(r1_1); tx.enlistResource(r1_2); tx.enlistResource(r2_1); tx.enlistResource(r2_2); tx.delistResource(r1_1, XAResource.TMSUCCESS); tx.delistResource(r1_2, XAResource.TMSUCCESS); tx.delistResource(r2_1, XAResource.TMSUCCESS); tx.delistResource(r2_2, XAResource.TMSUCCESS); tx.commit(); assertEquals(Status.STATUS_NO_TRANSACTION, tm.getStatus()); assertTrue((r1_1.isCommitted() & r1_1.isPrepared()) ^ (r1_2.isCommitted() & r1_2.isPrepared())); assertTrue(!r1_1.isRolledback() & !r1_2.isRolledback()); assertTrue((r2_1.isCommitted() & r2_1.isPrepared()) ^ (r2_2.isCommitted() & r2_2.isPrepared())); assertTrue(!r2_1.isRolledback() & !r2_2.isRolledback()); } //BE VERY CAREFUL!! the ResourceManager only "recovers" the LAST resource it creates. //This test depends on using the resource that will be recovered by the resource manager. public void testSimpleRecovery() throws Exception { //create a transaction in our own transaction manager Xid xid = tm.xidFactory.createXid(); Transaction tx = tm.importXid(xid, 0); tm.resume(tx); assertSame(tx, tm.getTransaction()); tx.enlistResource(r1_2); tx.enlistResource(r2_2); tx.delistResource(r1_2, XAResource.TMSUCCESS); tx.delistResource(r2_2, XAResource.TMSUCCESS); tm.suspend(); tm.prepare(tx); //recover tm.recovery.recoverLog(); resourceManagers.add(rm1); assertTrue(r1_2.isCommitted()); assertTrue(!r2_2.isCommitted()); resourceManagers.add(rm2); assertTrue(r2_2.isCommitted()); assertTrue(tm.recovery.localRecoveryComplete()); } public void testImportedXidRecovery() throws Exception { //create a transaction from an external transaction manager. XidFactory xidFactory2 = new XidFactoryImpl("tm2".getBytes()); Xid xid = xidFactory2.createXid(); Transaction tx = tm.importXid(xid, 0); tm.resume(tx); assertSame(tx, tm.getTransaction()); tx.enlistResource(r1_2); tx.enlistResource(r2_2); tx.delistResource(r1_2, XAResource.TMSUCCESS); tx.delistResource(r2_2, XAResource.TMSUCCESS); tm.suspend(); tm.prepare(tx); //recover tm.recovery.recoverLog(); resourceManagers.add(rm1); assertTrue(!r1_2.isCommitted()); assertTrue(!r2_2.isCommitted()); resourceManagers.add(rm2); assertTrue(!r2_2.isCommitted()); //there are no transactions started here, so local recovery is complete assertTrue(tm.recovery.localRecoveryComplete()); Map recovered = tm.getExternalXids(); assertEquals(1, recovered.size()); assertEquals(xid, recovered.keySet().iterator().next()); } public void testTimeout() throws Exception { long timeout = tm.getTransactionTimeoutMilliseconds(0L); tm.setTransactionTimeout((int)timeout/4000); tm.begin(); System.out.println("Test to sleep for" + timeout + " secs"); Thread.sleep(timeout); try { tm.commit(); fail("Tx Should get Rollback exception"); }catch(RollbackException rex) { // Caught expected exception } // Now test if the default timeout is active tm.begin(); System.out.println("Test to sleep for" + (timeout/2) + " secs"); Thread.sleep((timeout/2)); tm.commit(); // Its a failure if exception occurs. } public void testResourceManagerContract() throws Exception { resourceManagers.add(rm1); assertTrue(rm1.areAllResourcesReturned()); } private static class TestReferenceCollection extends ArrayList implements ReferenceCollection { ReferenceCollectionListener referenceCollectionListener; public void addReferenceCollectionListener(ReferenceCollectionListener listener) { this.referenceCollectionListener = listener; } public void removeReferenceCollectionListener(ReferenceCollectionListener listener) { this.referenceCollectionListener = null; } public boolean add(Object o) { boolean result = super.add(o); if (referenceCollectionListener != null) { referenceCollectionListener.memberAdded(new ReferenceCollectionEvent(null, o)); } return result; } public boolean remove(Object o) { boolean result = super.remove(o); if (referenceCollectionListener != null) { referenceCollectionListener.memberRemoved(new ReferenceCollectionEvent(null, o)); } return result; } public ObjectName[] getMemberObjectNames() {return new ObjectName[0];} } }